#include "TcpServer.h"
#include <arpa/inet.h>
#include <string.h>

struct st_args
{
    char *ip; // 客户端的ip地址
    int fd;   // 客户端的文件描述符fd
};

TcpServer::TcpServer()
{
    // 初始化事件集合
    m_base = event_base_new();
    if (!m_base)
    {
        printf("create event_base failed.\n");
        exit(1);
    }

    // 初始化线程池
    m_poolSize = 10;
    m_threadPool = new Thread[m_poolSize];
    currentThread = 0;
}

TcpServer::~TcpServer()
{
    // 释放资源
    event_base_free(m_base);
    evconnlistener_free(m_listener);
}

int TcpServer::listen(char *ip, short port)
{
    // 服务器地址结构
    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(port);
    inet_pton(AF_INET, ip, &server_addr.sin_addr.s_addr);
    // 创建监听对象
    m_listener = evconnlistener_new_bind(m_base, listener_cb, this, LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE,
                                         10, (struct sockaddr *)&server_addr, sizeof(server_addr));
    if (!m_listener)
    {
        printf("evconnlistener_new_bind error.\n");
        exit(1);
    }

    // 开启线程池
    for (int i = 0; i < m_poolSize; i++)
        m_threadPool[i].start();

    // 进入事件循环,开始监听
    event_base_dispatch(m_base);

    printf("server done.\n");
    return 0;
}

void TcpServer::listener_cb(evconnlistener *listener, evutil_socket_t fd, sockaddr *addr, int socklen, void *arg)
{
    TcpServer *s = (TcpServer *)arg;

    // 获取客户端的ip和port
    struct sockaddr_in *client_addr = (struct sockaddr_in *)addr;
    struct st_args args;
    args.ip = inet_ntoa(client_addr->sin_addr);
    args.fd = fd;

    printf("客户端(%s)[%d] 已连接.\n", args.ip, (int)fd);

    // 线程的轮询操作
    printf("线程 %ld 开始监听客户端(%s)[%d]\n", s->m_threadPool[s->currentThread].getThreadID(), args.ip, (int)fd);
    // 将客户端的通信套接字转化为事件,添加到线程的事件集合中
    s->m_threadPool[s->currentThread].addEvent(fd);
    // 取余,轮询操作 确保每个线程处理 负载均衡
    s->currentThread = (s->currentThread + 1) % s->m_poolSize;
}
